package com.tencent.welink.iot;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tencent.welink.sm.SM4Utils;
import com.tencent.welink.util.CrontabUtil;
import com.tencent.welink.util.RandomUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.paho.client.mqttv3.MqttException;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Created by limye on 2020/7/7.
 */
public class WelinkHttp {
    private static final Logger log = LogManager.getLogger(WelinkHttp.class);

    private String HOST;
    private String din;
    public String TOPIC;
    private String wId;

    private String SEND_URL;
    private String RECEIVE_URL;
    private String SEND_URL_SUFFIX = "/iotmsg/httpmsg/v1/send";
    private String RECEIVE_URL_SUFFIX = "/iotmsg/httpmsg/v1/pull";

    protected LoginData loginData;
    WelinkHttpSend welinkHttpSend = new WelinkHttpSend();

    protected List<SubDeviceDTO> subDeviceDTOList = new ArrayList<>();

    private AtomicLong seq = new AtomicLong(1);

    private WelinkHttpReceive welinkHttpReceive;

    public WelinkHttp(RegisterData registerData, LoginData loginData) {
        this.loginData = loginData;
        this.wId = registerData.wId;
        this.din = registerData.din;
        SEND_URL = registerData.httpDomain + SEND_URL_SUFFIX;
        RECEIVE_URL = registerData.httpDomain + RECEIVE_URL_SUFFIX;
    }

    /**
     * mqtt初始化
     */
    public void startConnect() {
        welinkHttpReceive = new WelinkHttpReceive(this, RECEIVE_URL,this.wId);
        welinkHttpReceive.schedulePullData();
        scheduleSendHeart();
        sendSubDeviceRegister();
        scheduleGetSubDevice();
        scheduleSendSubDeviceHeart();
    }

    /**
     * 定时发送心跳
     */
    private void scheduleSendHeart() {
        CrontabUtil.addTaskInRate(() -> {
            try {
                this.sendMessage(loginData.load(), 30001, "welink", true);
            } catch (Exception e) {
                log.error("发送mqtt消息失败：", e);
                //System.exit(0);
            }
        }, 20000, true);
    }


    public void sendMessage(String secretKey, String iv, JSONObject jsonObject) throws MqttException {
        byte[] encryptData = SM4Utils.encryptDataCBC(jsonObject.toJSONString().getBytes(), secretKey, iv);
        welinkHttpSend.getHeaderPara().put("wId", wId);
        welinkHttpSend.getHeaderPara().put("token", loginData.httpToken);
        welinkHttpSend.doResultByHttpPost(SEND_URL, encryptData);
    }

    public void sendMessage(String secretKey, String iv, int datapoint, String value, String report) throws MqttException {
        JSONObject msgJson = new JSONObject();
        msgJson.put("msgType", report);
        msgJson.put("seq", seq.getAndIncrement());
        msgJson.put("random", RandomUtil.getRandomInt());
        msgJson.put("timeStamp", System.currentTimeMillis());
        msgJson.put("datapoint", datapoint);
        msgJson.put("din", din);
        msgJson.put("wId", wId);
        msgJson.put("value", value);
        log.info("send mqtt message:" + msgJson.toString());
        this.sendMessage(secretKey, iv, msgJson);
    }


    public void sendMessage(String secretKey, String iv, int datapoint, long suDin, String value, String report) throws MqttException {
        JSONObject msgJson = new JSONObject();
        msgJson.put("msgType", report);
        msgJson.put("seq", seq.getAndIncrement());
        msgJson.put("random", RandomUtil.getRandomInt());
        msgJson.put("timeStamp", System.currentTimeMillis());
        msgJson.put("datapoint", datapoint);
        msgJson.put("din", din);
        msgJson.put("subDin", suDin);
        msgJson.put("wId", wId);
        msgJson.put("value", value);
        log.info("send mqtt message:" + msgJson.toString());
        this.sendMessage(secretKey, iv, msgJson);
    }


    public void sendMessage(String secretKey, String iv, int datapoint, long suDin, JSONObject value, String report) throws MqttException {
        JSONObject msgJson = new JSONObject();
        msgJson.put("msgType", report);
        msgJson.put("seq", seq.getAndIncrement());
        msgJson.put("random", RandomUtil.getRandomInt());
        msgJson.put("timeStamp", System.currentTimeMillis());
        msgJson.put("datapoint", datapoint);
        msgJson.put("din", din);
        msgJson.put("subDin", suDin);
        msgJson.put("wId", wId);
        msgJson.put("value", value);
        log.info("send mqtt message:" + msgJson.toString());
        this.sendMessage(secretKey, iv, msgJson);
    }

    public void sendMessage(LoginData loginData, int datapoint,long suDin, String value, boolean report) throws MqttException {
        this.sendMessage(loginData.ran, loginData.sm4IV, datapoint,suDin, value, report ? "report" : "ack");
    }

    public void sendMessage(LoginData loginData, int datapoint, String value, boolean report) throws MqttException {
        this.sendMessage(loginData.ran, loginData.sm4IV, datapoint, value, report ? "report" : "ack");
    }

    /**
     * 视频网关向后台请求子设备列表消息
     */
    public void requestSubDevice() {
        /**
         * 4.	30007：视频网关向后台请求子设备列表消息
         * a)	din: 视频网关的din
         * b)	timestamp: 当前时间，自1970年1月1日0时起的毫秒数
         * c)	message_id：30007
         * d)	message_content： "welink"
         * e)	msgType： data_report
         */
        try {
            this.sendMessage(loginData, 30007, "welink", true);
        } catch (MqttException e) {
            log.error("发送mqtt消息失败：", e);
        }
    }


    /**
     * 注册子设备
     */
    public void sendSubDeviceRegister() {
        /**
         * key	value	description
         * wId	String	网关设备唯一标识
         * msgType	String	report：主动发送，ack：查询返回，固定report
         * seq	Long	消息序号
         * random	Integer	随机数
         * timeStamp	Long	时间戳，单位：毫秒
         * datapoint	Integer	datapoint id，通电后上报dp：30010
         * value	String	消息自定义内容
         * pid	String	产品id
         * sn	String	设备sn
         * page	Integer	第几页
         * pageSize	Integer	一页多少记录,最多100
         * total	Integer	总记录数
         */


        if (this.din.equalsIgnoreCase("300000000000070736")) {
            SubDeviceDTO subDeviceDTO = new SubDeviceDTO();
            subDeviceDTO.setPid("1701000301");
            subDeviceDTO.setSn("limyezhaoming000103");
            SubDeviceDTO subDeviceDTO2 = new SubDeviceDTO();
            subDeviceDTO2.setPid("1701000299");
            subDeviceDTO2.setSn("limyezhaoming000102");
            List<SubDeviceDTO> list = new ArrayList<>();
            list.add(subDeviceDTO);
            list.add(subDeviceDTO2);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("page", 1);
            jsonObject.put("pagesize", list.size());
            jsonObject.put("total", list.size());
            JSONArray jsonArray = new JSONArray();
            for (SubDeviceDTO deviceDTO : list) {
                JSONObject object = new JSONObject();
                object.put("pid", deviceDTO.getPid());
                object.put("sn", deviceDTO.getSn());
                jsonArray.add(object);
            }
            jsonObject.put("deviceList", jsonArray);
            try {
                Thread.sleep(1000L);
                this.sendMessage(loginData.load(), 30010, jsonObject.toString(), true);
            } catch (Exception e) {
                log.error("发送mqtt消息失败：", e);
            }
        }

        if (this.din.equalsIgnoreCase("300000000000070741")) {
            SubDeviceDTO subDeviceDTO = new SubDeviceDTO();
            subDeviceDTO.setPid("1701000303");
            subDeviceDTO.setSn("limyetingchechang002");
            SubDeviceDTO subDeviceDTO2 = new SubDeviceDTO();
            subDeviceDTO2.setPid("1701000317");
            subDeviceDTO2.setSn("limyezhaji002");
            List<SubDeviceDTO> list = new ArrayList<>();
            list.add(subDeviceDTO);
            list.add(subDeviceDTO2);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("page", 1);
            jsonObject.put("pagesize", list.size());
            jsonObject.put("total", list.size());
            JSONArray jsonArray = new JSONArray();
            for (SubDeviceDTO deviceDTO : list) {
                JSONObject object = new JSONObject();
                object.put("pid", deviceDTO.getPid());
                object.put("sn", deviceDTO.getSn());
                jsonArray.add(object);
            }
            jsonObject.put("deviceList", jsonArray);
            try {
                Thread.sleep(1000L);
                this.sendMessage(loginData.load(), 30010, jsonObject.toString(), true);
            } catch (Exception e) {
                log.error("发送mqtt消息失败：", e);
            }
        }

        //300000000000073199
        if (this.din.equalsIgnoreCase("300000000000073199")) {
            SubDeviceDTO subDeviceDTO = new SubDeviceDTO();
            subDeviceDTO.setPid("1701000317");
            subDeviceDTO.setSn("limyezhaji003");
            SubDeviceDTO subDeviceDTO2 = new SubDeviceDTO();
            subDeviceDTO2.setPid("1701000317");
            subDeviceDTO2.setSn("limyezhaji004");
            List<SubDeviceDTO> list = new ArrayList<>();
            list.add(subDeviceDTO);
            list.add(subDeviceDTO2);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("page", 1);
            jsonObject.put("pagesize", list.size());
            jsonObject.put("total", list.size());
            JSONArray jsonArray = new JSONArray();
            for (SubDeviceDTO deviceDTO : list) {
                JSONObject object = new JSONObject();
                object.put("pid", deviceDTO.getPid());
                object.put("sn", deviceDTO.getSn());
                jsonArray.add(object);
            }
            jsonObject.put("deviceList", jsonArray);
            try {
                Thread.sleep(1000L);
                this.sendMessage(loginData.load(), 30010, jsonObject.toString(), true);
            } catch (Exception e) {
                log.error("发送mqtt消息失败：", e);
            }
        }

    }

    /**
     * 定时请求子设备列表
     */
    public void scheduleGetSubDevice() {
        new Thread(() -> {
            try {
                while (this.subDeviceDTOList.isEmpty()) {
                    Thread.sleep(12000L);
                    requestSubDevice();
                    welinkHttpReceive.pullMsg();
                    Thread.sleep(180000L);
                }
            } catch (Exception e) {
                log.error("发送mqtt消息失败：", e);
                // System.exit(0);
            }
        }).start();


    }

    /**
     * 定时发送子设备心跳
     */
    public void scheduleSendSubDeviceHeart() {
        CrontabUtil.addTaskInRate(() -> {
            try {
                if (!this.subDeviceDTOList.isEmpty()) {
                    /**
                     * a)	din: 视频网关的din
                     * b)	timestamp: 当前时间，自1970年1月1日0时起的毫秒数
                     * c)	message_id：30007
                     * d)	message_content： 子设备状态列表，Json字符串，包含以下信息
                     * i.	page: 1
                     * ii.	pagesize: 1
                     * iii.	total: 本次上报设备数
                     * iv.	deviceList: Json Array，每个元素为一个Json object，含两个字段：
                     * 1.	din: 摄像头din
                     * 2.	status: 状态，字符串，取值：online – 在线，offline – 离线
                     * e)	msgType： data_report
                     */
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("page", 1);
                    jsonObject.put("pagesize", 1);
                    jsonObject.put("total", subDeviceDTOList.size());
                    JSONArray jsonArray = new JSONArray();
                    for (SubDeviceDTO deviceDTO : subDeviceDTOList) {
                        JSONObject object = new JSONObject();
                        object.put("din", deviceDTO.getDin());
                        object.put("status", deviceDTO.getStatus());
                        jsonArray.add(object);
                    }
                    jsonObject.put("deviceList", jsonArray);
                    this.sendMessage(loginData.load(), 30002, jsonObject.toString(), true);
                }
            } catch (Exception e) {
                log.error("发送mqtt消息失败：", e);
                //System.exit(0);
            }
        }, 20000, true);
    }
}
